﻿namespace WebPacker.Tests.Configuration
{
	using System.IO;
	using System.Text;
	using System.Xml;
	using NUnit.Framework;
	using WebPacker.Configuration;
	using WebPacker.Filters;
	using WebPacker.Logger;
	using WebPacker.Packs;
	using WebPacker.Providers;
	using WebPacker.VersionGenerators;
	using Yahoo.Yui.Compressor;

	[TestFixture]
	public class WebPackerConfigurationTest
	{
		[Test]
		public void CreateRouterTest()
		{
			var config = GetConfiguration("complex");
			var router = config.CreateRouter();
		}

		[Test]
		public void DeserializeNullLoggerTest()
		{
			var config = GetConfiguration("logger1");
			var logger = config.Logger;
			Assert.IsNotNull(logger);
			Assert.IsInstanceOf<NullLogger>(logger);
			Assert.IsTrue(logger.Enabled);
		}

		[Test]
		public void DeserializeNLogLoggerTest()
		{
			var config = GetConfiguration("logger2");
			var logger = config.Logger;
			Assert.IsNotNull(logger);
			Assert.IsInstanceOf<NLogLogger>(logger);
			Assert.IsTrue(logger.Enabled);
			Assert.AreEqual("web.packer", ((NLogLogger)logger).Name);
		}

		[Test]
		public void DeserializePacksTest(
			[Values(true, false)]
			bool fromSourceFile)
		{
			PackInfoCollection actual;

			if (fromSourceFile)
			{
				actual = GetPackCollection("packs-source");
			}
			else
			{
				actual = GetConfiguration("packs").Packs;
			}

			Assert.IsNotNull(actual);
			Assert.AreEqual(true, actual.Monitoring);
			Assert.AreEqual("lastModified", actual.VersionGeneratorName);
			Assert.AreEqual(3, actual.Count);

			var expected = new PackInfo[]
			{
				new PackInfo
				{
					Name = "pack1",
					PackType = PackType.JavaScript,
					BasePath = "~/scripts",
					Monitoring = true,
					FilterName = "js",
					Version = "1.0",
					VersionGeneratorName = "manual",
					Resources = new ResourceInfo[]
					{
						new ResourceInfo
						{
							Name = "jquery-1.4.4.js",
							Encoding = Encoding.GetEncoding(1251)
						},
						new ResourceInfo("jquery-ui.js")
					}
				},
				new PackInfo
				{
					Name = "pack2",
					PackType = PackType.Css,
					BasePath = "~/css",
					Monitoring = false,
					FilterName = "css",
					VersionGeneratorName = "md5",
					Resources = new ResourceInfo[]
					{
						new ResourceInfo("styles1.css"),
						new ResourceInfo("styles2.css")
					}
				},
				new PackInfo
				{
					Name = "pack3",
					PackType = PackType.JavaScript,
					FilterName = "js",
					Monitoring = null,
					VersionGeneratorName = null,
					BasePath = null,
					Version = null,
					Resources = new ResourceInfo[] 
					{ 
						new ResourceInfo("script1.js")
						{
							Encoding = Encoding.Unicode
						}
					}
				}
			};

			Assert.That(actual, Is.EqualTo(expected).Using(new PackInfoEqualityComparer()));
		}

		[Test]
		public void DeserializeMemoryProviderTest(
			[Values("memoryProvider")]
			string testConfigName)
		{
			var config = GetConfiguration(testConfigName);
			Assert.IsNotNull(config.Provider);
			Assert.IsInstanceOf<MemoryPackProvider>(config.Provider);
			var provider = (MemoryPackProvider)config.Provider;
			Assert.AreEqual("~/webpacker.axd", provider.Url);
			Assert.AreEqual(1000, provider.CacheDuration);
			Assert.AreEqual(true, provider.SetLastModified);
		}

		[Test]
		public void DeserializeFileSystemProviderTest(
			[Values("fileSystemProvider1", "fileSystemProvider2")]
			string testConfigName)
		{
			var config = GetConfiguration(testConfigName);
			Assert.IsNotNull(config.Provider);
			Assert.IsInstanceOf<FileSystemPackProvider>(config.Provider);
			var provider = (FileSystemPackProvider)config.Provider;
			Assert.AreEqual("~/scripts/compile", provider.OutputPath);
		}

		[Test]
		public void DeserializeFiltersTest(
			[Values("filters1", "filters2")]
			string testConfigName)
		{
			var config = GetConfiguration(testConfigName);
			Assert.IsNotNull(config.Filters);
			Assert.AreEqual(2, config.Filters.Length);

			Assert.IsInstanceOf<YuiCssMinifier>(config.Filters[0]);
			Assert.IsInstanceOf<YuiJavascriptMinifier>(config.Filters[1]);

			var filter1 = (YuiCssMinifier)config.Filters[0];
			Assert.AreEqual(PackType.Css, filter1.PackType);
			Assert.AreEqual("css", filter1.Name);
			Assert.AreEqual(1000, filter1.ColumnWidth);
			Assert.AreEqual(CssCompressionType.StockYuiCompressor, filter1.CompressionType);

			var filter2 = (YuiJavascriptMinifier)config.Filters[1];
			Assert.AreEqual(PackType.JavaScript, filter2.PackType);
			Assert.AreEqual("js", filter2.Name);
			Assert.AreEqual(true, filter2.PreserveAllSemicolons);
			Assert.AreEqual(true, filter2.DisableOptimizations);
			Assert.AreEqual(false, filter2.IsObfuscateJavascript);
			Assert.AreEqual(1000, filter2.LineBreakPosition);
		}

		[Test]
		public void DeserializeVersionGeneratorTest()
		{
			var config = GetConfiguration("versionGenerators");
			Assert.IsNotNull(config.VersionGenerators);
			Assert.AreEqual(2, config.VersionGenerators.Length);

			var generator1 = config.VersionGenerators[0];
			Assert.IsNotNull(generator1);
			Assert.AreEqual("md5", generator1.Name);
			Assert.IsInstanceOf<Md5VersionGenerator>(generator1);

			var generator2 = config.VersionGenerators[1];
			Assert.IsNotNull(generator2);
			Assert.AreEqual("lastModified", generator2.Name);
			Assert.IsInstanceOf<LastModifiedVersionGenerator>(generator2);
		}

		[Test]
		public void DeserializeComplexTest()
		{
			var config = GetConfiguration("complex");

			Assert.AreEqual(false, config.Enabled);
			Assert.AreEqual(false, config.Compression);
			Assert.AreEqual(true, config.ThrowsExceptions);
			Assert.AreEqual(5000, config.MonitoringDelay);

			Assert.IsNotNull(config.Provider);
			Assert.IsInstanceOf<FileSystemPackProvider>(config.Provider);
			var packProvider = (FileSystemPackProvider)config.Provider;
			Assert.AreEqual(packProvider.OutputPath, "~/scripts/compile");

			Assert.IsNotNull(config.Logger);
			Assert.IsInstanceOf<NullLogger>(config.Logger);

			Assert.IsNotNull(config.Filters);
			Assert.AreEqual(2, config.Filters.Length);
			Assert.IsNotNull(config.Filters[0]);
			Assert.IsNotNull(config.Filters[1]);
			Assert.IsInstanceOf<YuiCssMinifier>(config.Filters[0]);
			Assert.IsInstanceOf<YuiJavascriptMinifier>(config.Filters[1]);

			var filter1 = (YuiCssMinifier)config.Filters[0];
			Assert.AreEqual(PackType.Css, filter1.PackType);
			Assert.AreEqual("css", filter1.Name);
			Assert.AreEqual(1000, filter1.ColumnWidth);
			Assert.AreEqual(CssCompressionType.StockYuiCompressor, filter1.CompressionType);

			var filter2 = (YuiJavascriptMinifier)config.Filters[1];
			Assert.AreEqual(PackType.JavaScript, filter2.PackType);
			Assert.AreEqual("js", filter2.Name);
			Assert.AreEqual(true, filter2.PreserveAllSemicolons);
			Assert.AreEqual(true, filter2.DisableOptimizations);
			Assert.AreEqual(false, filter2.IsObfuscateJavascript);
			Assert.AreEqual(1000, filter2.LineBreakPosition);

			Assert.IsNotNull(config.Packs);
			Assert.AreEqual(1, config.Packs.Count);
			Assert.AreEqual(null, config.Packs.Monitoring);
			Assert.AreEqual("md5", config.Packs.VersionGeneratorName);

			var packInfo = new PackInfo
			{
				Name = "pack1",
				PackType = PackType.JavaScript,
				BasePath = "~/scripts",
				Monitoring = true,
				FilterName = "js",
				Version = "1.2.3",
				VersionGeneratorName = "manual",
				Resources = new ResourceInfo[] { new ResourceInfo("script.js") }
			};

			Assert.That(config.Packs[0], Is.EqualTo(packInfo).Using(new PackInfoEqualityComparer()));
		}

		private PackInfoCollection GetPackCollection(string configName)
		{
			using (var streamReader = File.OpenText(string.Format("samples/configuration/{0}.xml", configName)))
			using (var xmlReader = XmlReader.Create(streamReader))
			{
				return WebPackerConfiguration.DeserializePackInfoCollection(xmlReader);
			}
		}

		private WebPackerConfiguration GetConfiguration(string configName)
		{
			using (var streamReader = File.OpenText(string.Format("samples/configuration/{0}.xml", configName)))
			using (var xmlReader = XmlReader.Create(streamReader))
			{
				return WebPackerConfiguration.Deserialize(xmlReader);
			}
		}
	}
}
